<!--
 * @Description: 在线用户管理
 * @Author: 月间
 * @Date: 2024-11-14 21:09:55
 * @LastEditTime: 2025-10-12 00:16:49
 * @LastEditors:
-->
<script setup lang="tsx">
import { ref } from 'vue';
import type { Ref } from 'vue';
import { DataTableColumns, NDataTable, NButton, NSpace, NPopconfirm } from 'naive-ui';
import { fetchGetOnlineUsers, fetchGetUserDevices, fetchLogoutByToken, fetchDisable, fetchLogoutByLoginId } from '@/service/api/system-manage';
import { useAppStore } from '@/store/modules/app';
import { useTable, useTableOperate } from '@/hooks/common/table';
import { $t } from '@/locales';
import TableHeaderOperation from '@/components/advanced/table-header-operation.vue';
const appStore = useAppStore();

// 用户设备信息映射
const userDevicesMap = ref<Record<number, Api.SystemManage.TerminalInfoModel[]>>({
});
const showModal = ref(false);

// 定义接口
interface DisableModel {
  login_id: string;
  time: number;
}

// 使用类型安全的ref
const disableByTokenModel = ref<DisableModel>({
  login_id: '',
  time: 0
});

// 获取用户设备信息
async function getUserDevices(user_id: number) {
  try {
    const { data } = await fetchGetUserDevices(user_id);
    userDevicesMap.value[user_id] = data;
    return data;
  } catch (error) {
    console.error(`获取用户 ${user_id} 设备信息失败:`, error);
    return [];
  }
}

// 设备信息列定义
const columns_dict_data: DataTableColumns<Api.SystemManage.TerminalInfoModel> = [
  {
    title: '序号',
    key: 'index',
    minWidth: 60,
    align: 'center'
  },
  {
    title: '设备类型',
    minWidth: 100,
    key: 'device_type',
    align: 'center'
  },
  {
    title: '操作系统',
    minWidth: 100,
    key: 'os',
    align: 'center',
    render: row => {
      if (!row.extra_data) return '-';
      return row.extra_data.os || '-';
    }
  },
  {
    title: '浏览器',
    minWidth: 100,
    key: 'browser',
    align: 'center',
    render: row => {
      if (!row.extra_data) return '-';
      return row.extra_data.browser || '-';
    }
  },
  {
    title: 'IP地址',
    minWidth: 120,
    key: 'ip',
    align: 'center',
    render: row => {
      if (!row.extra_data) return '-';
      return row.extra_data.ipaddr || '-';
    }
  },
  {
    title: '登录时间',
    minWidth: 150,
    key: 'create_time',
    align: 'center',
    render: row => {
      if (!row.create_time) return '-';
      return new Date(row.create_time).toLocaleString();
    }
  },
  // 禁用、封禁功能
  {
    title: '操作',
    key: 'action',
    align: 'center',
    render: row => {
      return (
        <NSpace justify="center">
          <NPopconfirm
            onPositiveClick={() => handleLogoutByToken(row.token_value)}
            v-slots={{
              trigger: () => (
                <NButton type="primary" size="small">
                  注销
                </NButton>
              )
            }}
          >
            确认注销吗？
          </NPopconfirm>
        </NSpace>
      );
    }
  }
];

// 注销功能
async function handleLogoutByToken(token_value: string) {
  try {
    const { data } = await fetchLogoutByToken(token_value);
    window.$message?.success(data?.msg || $t('common.deleteSuccess'));
    await getData();
    // 刷新嵌套表格数据 - 清除userDevicesMap，让它在展开时重新获取最新数据
    userDevicesMap.value = {};
  } catch (error) {
    window.$message?.error($t('common.deleteError'));
  }
}
// 打开模态框
function openModal(login_id: string) {
  showModal.value = true;
  disableByTokenModel.value.login_id = login_id;
}
// 禁用功能
async function handleDisableByToken() {
  try {
    const { data } = await fetchDisable(disableByTokenModel.value.login_id, disableByTokenModel.value.time);
    window.$message?.success(data?.msg || $t('common.deleteSuccess'));
    await getData();
    // 刷新嵌套表格数据 - 清除userDevicesMap，让它在展开时重新获取最新数据
    userDevicesMap.value = {};
  } catch (error) {
    window.$message?.error($t('common.deleteError'));
  }
}
const {
  columns,
  columnChecks,
  data,
  loading,
  getData,
  mobilePagination,
  searchParams,
  resetSearchParams
} = useTable({
  apiFn: fetchGetOnlineUsers,
  apiParams: {
    current: 1,
    size: 10,
  },
  columns: () => [
    {
      type: 'selection',
      align: 'center',
      width: 48
    },
    {
      type: 'expand',
      renderExpand: rowData => {
        if (userDevicesMap.value[rowData.id]) {
          return <NDataTable columns={columns_dict_data} data={userDevicesMap.value[rowData.id] || []} />;
        }
        getUserDevices(rowData.id);
        return <div>loading...</div>;
      }
    },
    {
      key: 'id',
      title: $t('common.index'),
      width: 64,
      align: 'center'
    },
    {
      key: 'nickname',
      title: '用户昵称',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'username',
      title: '用户名',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'deviceCount',
      title: '在线设备数',
      align: 'center',
      minWidth: 100
    },
    {
      key: 'updatedAt',
      title: '最后登录时间',
      align: 'center',
      minWidth: 150,
      render(row) {
        if (!row.updatedAt) return '-';
        return new Date(row.updatedAt).toLocaleString();
      }
    },
    // 操作
    {
      title: '操作',
      key: 'action',
      align: 'center',
      render: row => {
        return (
          <NSpace justify="center">
            <NPopconfirm
              onPositiveClick={() => handleForceLogout(row)}
              v-slots={{
                trigger: () => (
                  <NButton type="primary" size="small">
                    强制注销
                  </NButton>
                )
              }}
            >
              确认强制注销吗？
            </NPopconfirm>
            <NButton type="warning" size="small" onClick={() => openModal(row.id)}>
              封禁
          </NButton>
          </NSpace>
        );
      }
    }
  ]
});

const { checkedRowKeys, onBatchDeleted, onDeleted } = useTableOperate(data, getData);

// 由于是查看功能，批量删除功能可以保留但不实现具体逻辑
async function handleBatchDelete() {
  onBatchDeleted();
}

// 由于是查看功能，编辑功能可以保留但不实现具体逻辑
// 强制注销功能
async function handleForceLogout(item: Api.SystemManage.SimpleOnlineUser) {
  try {
    const { data } = await fetchLogoutByLoginId(item.id);
    window.$message?.success(data?.msg || '强制下线成功');
    await getData();
    // 刷新嵌套表格数据 - 清除userDevicesMap，让它在展开时重新获取最新数据
    userDevicesMap.value = {};
  } catch (error) {
    window.$message?.error('强制下线失败');
  }
}

function handleAdd() {
  console.log('添加在线用户记录');
}
</script>

<template>
  <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
    <NCard title="在线用户管理" :bordered="false" size="small" class="sm:flex-1-hidden card-wrapper">
      <template #header-extra>
        <TableHeaderOperation v-model:columns="columnChecks" :loading="loading" @refresh="getData">
          <template #prefix>
            <NButton size="small" ghost type="primary" @click="handleAdd">
              <template #icon>
                <icon-ic-round-plus class="text-icon" />
              </template>
              {{ $t('common.add') }}
            </NButton>
            <NPopconfirm @positive-click="handleBatchDelete">
              <template #trigger>
                <NButton size="small" ghost type="error" :disabled="checkedRowKeys.length === 0">
                  <template #icon>
                    <icon-ic-round-delete class="text-icon" />
                  </template>
                  {{ $t('common.batchDelete') }}
                </NButton>
              </template>
              {{ $t('common.confirmDelete') }}
            </NPopconfirm>
          </template>
        </TableHeaderOperation>
      </template>

      <NDataTable
        v-model:checked-row-keys="checkedRowKeys"
        :columns="columns"
        :data="data"
        size="small"
        :flex-height="!appStore.isMobile"
        :scroll-x="702"
        :loading="loading"
        remote
        :row-key="row => row.id"
        :pagination="mobilePagination"
        class="sm:h-full"
      />
    </NCard>
    <NModal
      v-model:show="showModal"
      preset="dialog"
      title="禁用时长"
      content="你确认?"
      positive-text="确认"
      negative-text="取消"
      @positive-click="handleDisableByToken"
    >
      <NInputNumber v-model:value="disableByTokenModel.time" placeholder="请输入禁用时间（单位：秒）" />
    </NModal>
  </div>
</template>

<style scoped>
.card-wrapper {
  display: flex;
  flex-direction: column;
}
</style>
